/* eslint-disable @typescript-eslint/ban-ts-comment */
import { v4 as uuidv4 } from 'uuid'
import 'ol/ol.css'
import Map from 'ol/Map'
import { ImageWMS, OSM, Vector as VectorSource } from 'ol/source'
import View from 'ol/View'
import { easeOut } from 'ol/easing'
import { toLonLat, fromLonLat } from 'ol/proj'
import { Tile as TileLayer, Vector as VectorLayer, Image as ImageLayer } from 'ol/layer'
import DrawInteraction from 'ol/interaction/Draw'
import type { Coordinate } from 'ol/coordinate'
import type { Type } from 'ol/geom/Geometry'
import type BaseLayer from 'ol/layer/Base'

interface MapOption {
  /**
   * 创建地图时默认的缩放级别, 如何设置了最小值, 那么默认就是最小值
   * @default 2
   */
  defaultZoom?: number
  /**
   * 创建地图时默认的中心点
   * @default
   * ```
   * {
   *    lng: 0,
   *    lat: 0
   * }
   * ```
   */
  defaultCenter?: {
    /** 经度 */
    lng: number
    /** 纬度 */
    lat: number
  }
  /**
   * 地图初始化时的旋转角度
   * @default 0
   */
  defaultRotation?: number
  /**
   * 最小缩放级别
   * @default 2
   */
  minZoom?: number
  /**
   * 最大缩放级别
   * @default 25
   */
  maxZoom?: number
  /**
   * 地图变化时的动画时长，单位: 毫秒
   * @default 0
   */
  animationDuration?: number
}

export type VectorType =
  | 'Point'
  | 'LineString'
  | 'LinearRing'
  | 'Polygon'
  | 'MultiPoint'
  | 'MultiLineString'
  | 'MultiPolygon'
  | 'GeometryCollection'
  | 'Circle'
  | 'None'

export type DrawVectorCallbackParam0 = { coordinates: Coordinate[]; type: VectorType; radius?: number; unit?: string }
export type DrawVectorCallback = (data: DrawVectorCallbackParam0) => void

function useMap(option: MapOption = {}) {
  const {
    defaultCenter = { lng: 0, lat: 0 },
    defaultZoom = 2,
    defaultRotation = 0,
    minZoom = 2,
    maxZoom = 25,
    animationDuration = 250
  } = option

  /**
   * 地图容器的id
   */
  const id = `map-${useId()}`

  /**
   * map instance
   */
  let map: Map | null = null
  /**
   * 当前地图的zoom
   */
  const currentZoom = ref(0)
  if (defaultZoom < minZoom) {
    currentZoom.value = minZoom
  } else {
    currentZoom.value = defaultZoom
  }
  /**
   * 当前鼠标位置的经纬度
   */
  const currentPointPosition = ref({ lng: 0, lat: 0 })
  /**
   * 当前地图的旋转角度
   */
  const currentRotation = ref(defaultRotation)
  /**
   * 当前地图是否正在漫游(拖拽中、缩放中、旋转中、平移中)
   */
  const isMoving = ref(false)

  /**
   * 初始化地图
   */
  function initMap() {
    // 判断存放地图的容器是否存在
    const target = document.getElementById(id)
    if (!target) {
      throw new Error(`存放地图的容器 [${id}] 不存在！`)
    }

    map = new Map({
      target,
      // layers: [tileLayer, ...airportLayers],
      view: new View({
        projection: 'EPSG:3857',
        center: fromLonLat([defaultCenter.lng, defaultCenter.lat]),
        zoom: currentZoom.value,
        minZoom,
        maxZoom,
        rotation: defaultRotation
      }),
      // 取消所有默认控件，控件自己编写html实现
      controls: []
    })

    listenerEvents()

    const tileLayer = new TileLayer({
      source: new OSM({
        wrapX: true
      })
    })
    tileLayer.set('id', 'osm:tile-layer')
    tileLayer.set('name', '地图底图')
    addLayer(tileLayer)
    /* const layer = new ImageLayer({
      source: new ImageWMS({
        projection: 'EPSG:4326',
        // url: 'http://localhost:8080/geoserver/airport/wms',
        url: 'http://59.110.31.122:36110/geoserver/base/wms',
        params: {
          SERVICE: 'WMS',
          VERSION: '1.1.1',
          REQUEST: 'GetMap',
          FORMAT: 'image/png',
          TRANSPARENT: true,
          LAYERS: 'base:beijing_blue'
        },
        ratio: 1,
        serverType: 'geoserver'
      })
    })
    layer.set('id', 'base:beijing_blue')
    layer.set('name', '地图底图')
    addLayer(layer) */
    // ;['airport:辅助车道图', 'airport:服务车道', 'airport:滑行线'].forEach(item => {
    ;['airport:airport_bj'].forEach(item => {
      const layer = new ImageLayer({
        source: new ImageWMS({
          projection: 'EPSG:4326',
          // url: 'http://localhost:8080/geoserver/airport/wms',
          url: 'http://59.110.31.122:36110/geoserver/airport/wms',
          params: {
            SERVICE: 'WMS',
            VERSION: '1.1.1',
            REQUEST: 'GetMap',
            FORMAT: 'image/png',
            TRANSPARENT: true,
            LAYERS: item
          },
          ratio: 1,
          serverType: 'geoserver'
        })
      })
      layer.set('id', item)
      layer.set('name', item.replace('airport:', ''))
      addLayer(layer)
    })
  }

  /**
   * 监听地图的事件
   */
  function listenerEvents() {
    if (!map) {
      return
    }

    const view = getView()
    // 监听地图zoom改变的事件
    view.on('change:resolution', () => {
      currentZoom.value = view.getZoom()!
    })
    // 监听地图旋转改变的事件
    view.on('change:rotation', () => {
      currentRotation.value = Math.round(getView().getRotation()! * (180 / Math.PI))
    })

    // 监听鼠标在地图上的移动事件
    map.on('pointermove', event => {
      // 获取地图上的鼠标坐标（像素坐标）
      const coordinate = event.coordinate
      // 将地图坐标转换为经纬度
      const [lng, lat] = toLonLat(coordinate)
      currentPointPosition.value = { lng, lat }
    })

    // 地图漫游开始
    map.on('movestart', () => {
      isMoving.value = true
    })
    // 地图漫游结束
    map.on('moveend', () => {
      isMoving.value = false
    })
  }

  // 全部图层
  const layers = shallowRef<BaseLayer[]>([])
  /**
   * 添加图层
   * @param layer 要添加的图层
   * @returns 图层的id
   */
  function addLayer(layer: BaseLayer) {
    let id = layer.get('id')
    if (!id) {
      id = `layer-${uuidv4()}`
    }
    layers.value.push(layer)
    map!.addLayer(layer)
    return id
  }
  /**
   * 移除图层
   * @param layer 要移除的图层
   */
  function removeLayer(layer: BaseLayer) {
    map!.removeLayer(layer)
    layers.value = layers.value.filter(item => item.get('id') !== layer.get('id'))
  }
  /**
   * 获取图层
   * @param id 图层的id
   * @returns 图层对象
   */
  function getLayer(id: string) {
    return map!.getAllLayers().find(item => item.get('id') === id)
  }

  /**
   * 获取地图的view
   * @returns
   */
  function getView() {
    return map!.getView()
  }

  /**
   * 设置地图的缩放级别
   * @param zoom 地图缩放级别
   */
  function setZoom(zoom: number) {
    const view = getView()
    view.animate({
      zoom: zoom,
      duration: animationDuration,
      easing: easeOut
    })
  }
  /**
   * 放大地图
   */
  function zoomIn() {
    setZoom(currentZoom.value + 1)
  }
  /**
   * 缩小地图
   */
  function zoomOut() {
    setZoom(currentZoom.value - 1)
  }
  /**
   * 设置zoom的最大值和最小值
   * @param range 最小值和最大值
   */
  function setZoomRange(range: { min?: number; max?: number }) {
    const view = getView()
    if (range.min) {
      view.setMinZoom(range.min)
    }
    if (range.max) {
      view.setMaxZoom(range.max)
    }
  }
  /**
   * 设置旋转角度
   * @param rotation 旋转角度
   */
  function setRotation(rotation: number) {
    const view = getView()
    view.animate({
      rotation: rotation * (Math.PI / 180),
      duration: animationDuration,
      easing: easeOut
    })
  }
  /**
   * 设置地图中心点（定位）
   * @param position 经纬度
   */
  function setCenter(position: { lng: number; lat: number }) {
    const view = getView()
    view.animate({
      center: fromLonLat([position.lng, position.lat]),
      duration: animationDuration,
      easing: easeOut
    })
  }

  /**
   * 绘制点、线、面、圆等机会图形
   * @param vector 绘制的图形类型
   * @param layer  要绘制的图层
   * @param callback 绘制完成后的回调函数
   * @returns layer
   */
  function drawVector(vector: VectorType, layer?: VectorLayer, callback?: DrawVectorCallback) {
    if (!map) return

    // 移除其他绘制图形的交互
    const interactions = map.getInteractions()
    for (let i = interactions.getLength(); i--; ) {
      const interaction = interactions.getArray()[i]
      if (interaction instanceof DrawInteraction) {
        map.removeInteraction(interaction)
      }
    }
    if (vector === 'None') {
      return
    }
    // 如果没有指定图层，则创建一个新图层
    if (!layer) {
      const source = new VectorSource({
        wrapX: false
      })
      layer = new VectorLayer({ source })
      map.addLayer(layer)
    }

    const draw = new DrawInteraction({
      source: layer.getSource()!,
      type: vector as Type
    })
    map.addInteraction(draw)

    draw.on('drawend', event => {
      const result: DrawVectorCallbackParam0 = {
        coordinates: [] as Array<number>[],
        type: vector
      }
      const geometry = event.feature.getGeometry()!
      // @ts-ignore
      const coordinates = geometry.getCoordinates()
      switch (geometry.getType()) {
        case 'Point': {
          result.coordinates = [coordinates] // [toLonLat(coordinates)]
          break
        }
        case 'Polygon': {
          coordinates[0].forEach((item: Coordinate) => {
            result.coordinates.push(toLonLat(item) as Array<number>)
          })
          break
        }
        case 'LineString': {
          coordinates.forEach((item: Coordinate) => {
            result.coordinates.push(toLonLat(item) as Array<number>)
          })
          break
        }
        case 'Circle': {
          // 圆心坐标
          // @ts-ignore
          result.coordinates = toLonLat(geometry.getCenter())
          // 圆的半径(投影单位，如 EPSG:3857 为米)
          // @ts-ignore
          result.radius = geometry.getRadius()
          // 投影单位
          result.unit = getView().getProjection().getUnits()
          break
        }
      }

      callback?.(result)
    })
    return layer
  }

  onMounted(() => {
    initMap()
  })

  onUnmounted(() => {
    // 解除所有事件绑定
    map!.getInteractions().clear()
    map!.getOverlays().clear()
    // 解除 DOM 容器绑定
    map!.setTarget(void 0)
  })

  return {
    id,
    currentZoom,
    currentPointPosition,
    currentRotation,
    isMoving,
    getView,
    setZoom,
    zoomIn,
    zoomOut,
    setZoomRange,
    setRotation,
    setCenter,
    drawVector,

    layers,
    addLayer,
    removeLayer,
    getLayer
  }
}

export default useMap
